package com.goldze.mvvmhabit.widght.expand;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ObservableList;
import androidx.databinding.OnRebindCallback;
import androidx.databinding.ViewDataBinding;
import androidx.recyclerview.widget.RecyclerView;

import com.goldze.mvvmhabit.utils.Utils;
import com.h6ah4i.android.widget.advrecyclerview.expandable.RecyclerViewExpandableItemManager;
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractExpandableItemAdapter;
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractExpandableItemViewHolder;

import java.lang.ref.WeakReference;
import java.util.List;

import me.goldze.mvvmhabit.utils.KLog;

public class ExpandedRvAdapter<T extends ExpandableViewModel>
        extends AbstractExpandableItemAdapter<ExpandedRvAdapter.ParentViewHolder, ExpandedRvAdapter.ChildViewHolder>
        implements BindExpandRvAdapter<T>{
    private RecyclerViewExpandableItemManager mExpandableItemManager;
    private ExpandItemBinding<T> mGroupItemBinding;
    private ExpandItemBinding<T> mChildItemBinding;
    private List<T> items;
    private LayoutInflater inflater;
    @Nullable
    private RecyclerView recyclerView;

    public ExpandedRvAdapter(RecyclerViewExpandableItemManager mExpandableItemManager) {
        KLog.e("sss  ");
        this.mExpandableItemManager = mExpandableItemManager;
        setHasStableIds(true);
    }

    private final WeakReferenceOnGroupListChangedCallback<T> groupCallback = new WeakReferenceOnGroupListChangedCallback<>(this);
    @Override
    public int getGroupCount() {
        KLog.e("sss  ");
        return items==null?0:items.size();
    }

    @Override
    public int getChildCount(int groupPosition) {
        KLog.e("sss  ");
        if(items==null){
            return 0;
        }
        return items.get(groupPosition).getChildCount();
    }

    @Override
    public long getGroupId(int groupPosition) {
        KLog.e("sss  ");
        return items.get(groupPosition).getId();
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        KLog.e("sss  ");
        return items.get(groupPosition).getChild(childPosition).getId();
    }

    @NonNull
    @Override
    public ParentViewHolder onCreateGroupViewHolder(ViewGroup parent, int viewType) {
        KLog.e("sss  ");
        if (inflater == null) {
            inflater = LayoutInflater.from(parent.getContext());
        }
        ViewDataBinding binding = onCreateBinding(inflater, viewType, parent);
        final ParentViewHolder holder = new ParentViewHolder(binding.getRoot());

        binding.addOnRebindCallback(new OnRebindCallback() {
            @Override
            public boolean onPreBind(ViewDataBinding binding) {
                return recyclerView != null && recyclerView.isComputingLayout();
            }

            @Override
            public void onCanceled(ViewDataBinding binding) {
                if (recyclerView == null || recyclerView.isComputingLayout()) {
                    return;
                }
                int position = holder.getAdapterPosition();
                if (position != RecyclerView.NO_POSITION) {
                    notifyItemChanged(position);
                }
            }
        });

        return holder;
    }

    @NonNull
    @Override
    public ChildViewHolder onCreateChildViewHolder(ViewGroup parent, int viewType) {
        KLog.e("sss  ");
        if (inflater == null) {
            inflater = LayoutInflater.from(parent.getContext());
        }
        ViewDataBinding binding = onCreateBinding(inflater, viewType, parent);
        final ChildViewHolder holder = new ChildViewHolder(binding.getRoot());

        binding.addOnRebindCallback(new OnRebindCallback() {
            @Override
            public boolean onPreBind(ViewDataBinding binding) {
                return recyclerView != null && recyclerView.isComputingLayout();
            }

            @Override
            public void onCanceled(ViewDataBinding binding) {
                if (recyclerView == null || recyclerView.isComputingLayout()) {
                    return;
                }
                int position = holder.getAdapterPosition();
                if (position != RecyclerView.NO_POSITION) {
                    notifyItemChanged(position);
                }
            }
        });

        return holder;
    }


    @Override
    public int getGroupItemViewType(int groupPosition) {
        KLog.e("sss  ");
        mGroupItemBinding.onItemBind(groupPosition, items.get(groupPosition));
        return mGroupItemBinding.layoutRes();
    }

    @Override
    public int getChildItemViewType(int groupPosition, int childPosition) {
        KLog.e("sss  ");
        mChildItemBinding.onItemBind(groupPosition, childPosition, (T)items.get(groupPosition).getChild(childPosition));
        return mChildItemBinding.layoutRes();
    }
    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        KLog.e("sss  "+recyclerView);
        KLog.e("sss  "+items);
        KLog.e("sss  "+( items instanceof ObservableList));
        if (this.recyclerView == null && items != null && items instanceof ObservableList) {
            ((ObservableList<T>) items).addOnListChangedCallback(groupCallback);
            KLog.e("sss  ");
            for (int i = 0; i < this.items.size(); i++) {
                ExpandableViewModel item = this.items.get(i);
                final WeakReferenceOnChildListChangedCallback<T> childCallback = new WeakReferenceOnChildListChangedCallback<>(this, i);

                if (item.getItems() instanceof ObservableList) {
                    ((ObservableList<T>) item.getItems()).addOnListChangedCallback(childCallback);
                }
            }
        }
        this.recyclerView = recyclerView;
    }

    @Override
    public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
        KLog.e("sss  ");
        if (this.recyclerView != null && items != null && items instanceof ObservableList) {
            ((ObservableList<T>) items).removeOnListChangedCallback(groupCallback);

            for (int i = 0; i < this.items.size(); i++) {
                ExpandableViewModel item = this.items.get(i);
                final WeakReferenceOnChildListChangedCallback<T> childCallback = new WeakReferenceOnChildListChangedCallback<>(this, i);

                if (item.getItems() instanceof ObservableList) {
                    ((ObservableList<T>) item.getItems()).removeOnListChangedCallback(childCallback);
                }
            }
        }
        this.recyclerView = null;
    }
    @Override
    public void onBindGroupViewHolder(@NonNull ParentViewHolder holder, int groupPosition, int viewType) {
        KLog.e("sss  ");
        T item = items.get(groupPosition);
        ViewDataBinding binding = DataBindingUtil.getBinding(holder.itemView);
        onBindGroupBinding(binding,mGroupItemBinding.variableId(),mGroupItemBinding.layoutRes(),groupPosition,item);
    }

    @Override
    public void onBindChildViewHolder(@NonNull ChildViewHolder holder, int groupPosition, int childPosition, int viewType) {
        KLog.e("sss  ");
        T item = (T) items.get(groupPosition).getChild(childPosition);
        ViewDataBinding binding = DataBindingUtil.getBinding(holder.itemView);
        onBindChildBinding(binding,mChildItemBinding.variableId(),mChildItemBinding.layoutRes(),groupPosition,childPosition,item);
    }

    @Override
    public boolean onCheckCanExpandOrCollapseGroup(@NonNull ParentViewHolder holder, int groupPosition, int x, int y, boolean expand) {
        KLog.e("sss  ");
        return true;
    }

    @Override
    public void setItemBinding(ExpandItemBinding m, ExpandItemBinding c) {
        this.mGroupItemBinding = m;
        this.mChildItemBinding = c;
    }

    @Override
    public ExpandItemBinding getGroupItemBinding() {
        KLog.e("sss  ");
        return mGroupItemBinding;
    }

    @Override
    public ExpandItemBinding getChildItemBinding() {
        KLog.e("sss  ");
        return mChildItemBinding;
    }

    @Override
    public T getAdapterItem(int position) {
        KLog.e("sss  ");
        return    items.get(position);
    }

    @Override
    public ViewDataBinding onCreateBinding(LayoutInflater inflater, int layoutRes, ViewGroup viewGroup) {
        KLog.e("sss  ");
        return DataBindingUtil.inflate(inflater,layoutRes,viewGroup,false);
    }

    @Override
    public void onBindChildBinding(ViewDataBinding binding, int variableId, int layoutRes, int groupPosition, int childPosition, T item) {
        KLog.e("sss  ");
        if(mChildItemBinding.bind(binding,item)){
            binding.executePendingBindings();
        }
    }

    @Override
    public void onBindGroupBinding(ViewDataBinding binding, int variableId, int layoutRes, int groupPosition, T item) {
        KLog.e("sss  ");
        if(mGroupItemBinding.bind(binding,item)){
            binding.executePendingBindings();
        }
    }

    @Override
    public void setItems(@Nullable List items) {
        KLog.e("sss  "+items.size()+ recyclerView);
        if (this.items == items) {
            return;
        }
        if (recyclerView != null) {
            if (this.items instanceof ObservableList) {
                ((ObservableList<T>) this.items).removeOnListChangedCallback(groupCallback);
            }
            if (items instanceof ObservableList) {
                ((ObservableList<T>) items).addOnListChangedCallback(groupCallback);
            }

            for (int i = 0; i < this.items.size(); i++) {
                ExpandableViewModel item = this.items.get(i);
                final WeakReferenceOnChildListChangedCallback<T> childCallback = new WeakReferenceOnChildListChangedCallback<>(this, i);
                if (item.getItems() instanceof ObservableList) {
                    ((ObservableList<T>) item.getItems()).removeOnListChangedCallback(childCallback);
                }
                if (item instanceof ObservableList) {
                    ((ObservableList<T>) item.getItems()).addOnListChangedCallback(childCallback);
                }
            }
        }
        this.items = items;
    }


    public static class ChildViewHolder extends BaseViewHolder{

        public ChildViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }
    public static class ParentViewHolder extends BaseViewHolder{

        public ParentViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }

    public static class  BaseViewHolder extends AbstractExpandableItemViewHolder{

        public BaseViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }

    private static class WeakReferenceOnGroupListChangedCallback<T extends ExpandableViewModel> extends ObservableList.OnListChangedCallback<ObservableList<T>> {
        final WeakReference<ExpandedRvAdapter<T>> adapterRef;

        WeakReferenceOnGroupListChangedCallback(ExpandedRvAdapter<T> adapter) {
            this.adapterRef = new WeakReference<>(adapter);
        }

        @Override
        public void onChanged(ObservableList sender) {
            ExpandedRvAdapter<T> adapter = adapterRef.get();
            if (adapter == null) {
                return;
            }
        }

        @Override
        public void onItemRangeChanged(ObservableList sender, final int positionStart, final int itemCount) {
            ExpandedRvAdapter<T> adapter = adapterRef.get();
            if (adapter == null) {
                return;
            }
            Utils.ensureChangeOnMainThread();
            adapter.mExpandableItemManager.notifyGroupAndChildrenItemsChanged(positionStart);
        }

        @Override
        public void onItemRangeInserted(ObservableList sender, final int positionStart, final int itemCount) {
            ExpandedRvAdapter<T> adapter = adapterRef.get();
            if (adapter == null) {
                return;
            }
            Utils.ensureChangeOnMainThread();
            adapter.mExpandableItemManager.notifyGroupItemRangeInserted(positionStart, itemCount);
        }

        @Override
        public void onItemRangeMoved(ObservableList sender, final int fromPosition, final int toPosition, final int itemCount) {
            ExpandedRvAdapter<T> adapter = adapterRef.get();
            if (adapter == null) {
                return;
            }
            Utils.ensureChangeOnMainThread();
            adapter.mExpandableItemManager.notifyGroupItemMoved(fromPosition, toPosition);
        }

        @Override
        public void onItemRangeRemoved(ObservableList sender, final int positionStart, final int itemCount) {
            ExpandedRvAdapter<T> adapter = adapterRef.get();
            if (adapter == null) {
                return;
            }
            Utils.ensureChangeOnMainThread();
            adapter.mExpandableItemManager.notifyGroupItemRangeRemoved(positionStart, itemCount);
        }
    }

    /////////////////////////////////////////////////
    //child data list listener
    private static class WeakReferenceOnChildListChangedCallback<T extends ExpandableViewModel> extends ObservableList.OnListChangedCallback<ObservableList<T>> {
        final WeakReference<ExpandedRvAdapter<T>> adapterRef;
        int groupPosition;

        WeakReferenceOnChildListChangedCallback(ExpandedRvAdapter<T> adapter, int groupPosition) {
            this.adapterRef = new WeakReference<>(adapter);
            this.groupPosition = groupPosition;
        }

        @Override
        public void onChanged(ObservableList sender) {
            ExpandedRvAdapter<T> adapter = adapterRef.get();
            if (adapter == null) {
                return;
            }
        }

        @Override
        public void onItemRangeChanged(ObservableList sender, final int positionStart, final int itemCount) {
            ExpandedRvAdapter<T> adapter = adapterRef.get();
            if (adapter == null) {
                return;
            }
            Utils.ensureChangeOnMainThread();
            adapter.mExpandableItemManager.notifyChildItemRangeChanged(groupPosition, positionStart, itemCount);
        }

        @Override
        public void onItemRangeInserted(ObservableList sender, final int positionStart, final int itemCount) {
            ExpandedRvAdapter<T> adapter = adapterRef.get();
            if (adapter == null) {
                return;
            }
            Utils.ensureChangeOnMainThread();
            adapter.mExpandableItemManager.notifyChildItemRangeInserted(groupPosition, positionStart, itemCount);
        }

        @Override
        public void onItemRangeMoved(ObservableList sender, final int fromPosition, final int toPosition, final int itemCount) {
            ExpandedRvAdapter<T> adapter = adapterRef.get();
            if (adapter == null) {
                return;
            }
            Utils.ensureChangeOnMainThread();
            adapter.mExpandableItemManager.notifyChildItemMoved(groupPosition, fromPosition, toPosition);
        }

        @Override
        public void onItemRangeRemoved(ObservableList sender, final int positionStart, final int itemCount) {
            ExpandedRvAdapter<T> adapter = adapterRef.get();
            if (adapter == null) {
                return;
            }
            Utils.ensureChangeOnMainThread();
            adapter.mExpandableItemManager.notifyChildItemRangeRemoved(groupPosition, positionStart, itemCount);
        }
    }
}
